/*
 * HttpServer.h
 *
 *  Created on: 2016-7-25
 *      Author: terry
 */

#ifndef HTTPSERVER_H_
#define HTTPSERVER_H_

#include <stdio.h>
#include <stdarg.h>
#include <iosfwd>
#include <string>
#include <map>
#include <sstream>
#include <cstring>
#include <functional>

#undef DELETE


typedef void   HttpConnection;

class HttpServer;


typedef std::map< std::string, std::string >	StringMap;
typedef std::pair< const char*, int >           IntString;


class HttpRequest
{
public:
    virtual ~HttpRequest() {}

    StringMap   urlParams;
    std::string token;

    virtual HttpServer* getServer() =0;

    virtual HttpConnection* getConnection() =0;

    virtual std::string getToken() =0;

    virtual std::string getMethod() =0;

    virtual bool isMethod(const char* method) =0;

    virtual std::string getUrl() =0;

    virtual std::string getQuery() =0;

    virtual const char* getBody(size_t& len) =0;

	virtual std::string getBody()
	{
		std::string body;
		size_t len = 0;
		const char* str = getBody(len);
		if (str && len > 0)
		{
			body.assign(str, len);
		}
		return body;
	}

    virtual bool getHeader(const char* name, std::string& value) =0;

    virtual bool getParam(const char* name, std::string& value) =0;


	template < class T >
	bool get(const std::string& name, T& value)
	{
		std::string str;
		if (!getParam(name.c_str(), str))
		{
			return false;
		}

		if (str.empty())
		{
			return false;
		}

		std::istringstream iss(str);
		iss >> value;
		return true;
	}

	template < class T >
	bool get(const char* name, T& value)
	{
		std::string str;
		if (!getParam(name, str))
		{
			return false;
		}

		if (str.empty())
		{
			return false;
		}

		std::istringstream iss(str);
		iss >> value;
		return true;
	}

	bool get(const std::string& name, std::string& value)
	{
		return getParam(name.c_str(), value);
	}

	bool get(const char* name, std::string& value)
	{
		return getParam(name, value);
	}

	bool get(const char* name, bool& value)
	{
		std::string str;
		if (!getParam(name, str))
		{
			return false;
		}

		if (str.empty())
		{
			return false;
		}

		return toBool(str, value);
	}

	bool get(const std::string& name, bool& value)
	{
		std::string str;
		if (!getParam(name.c_str(), str))
		{
			return false;
		}

		if (str.empty())
		{
			return false;
		}

		return toBool(str, value);
	}

	virtual std::string getFileName()
	{
		return std::string();
	}

	virtual std::string getFilePath()
	{
		return std::string();
	}

	bool toBool(const std::string& str, bool& value)
	{
		if (str == "0" || str == "false" || str == "False" || str == "FALSE")
		{
			value = false;
			return true;
		}
		else if (str == "1" || str == "true" || str == "True" || str == "TRUE")
		{
			value = true;
			return true;
		}

		std::istringstream iss(str);
		iss >> value;
		return true;
	}

};

class HttpResponse
{
public:
    virtual ~HttpResponse() {}

    virtual HttpConnection* getConnection() =0;

    virtual void setStatusCode(int code) =0;

    virtual void setHeader(const char* name, const std::string& value) =0;

    virtual void setMime(const char* mime) =0;

    virtual void setContent(const char* str, size_t len) =0;

    //virtual void write(const char* str, size_t len) =0;

};

struct HttpResult
{
    int code;
    StringMap headers;
    std::string mime;
    std::string content;

    HttpResult():
        code(200)
    {
    }
};

class HttpMethod
{
public:
	static const char* GET;
	static const char* POST;
	static const char* PUT;
	static const char* DELETE;
	static const char* OPTION;

};


class HttpHandler
{
public:
    virtual ~HttpHandler() {}

    virtual int handle(HttpRequest& request, HttpResult& result) =0;

};

/**
 * HTTP 服务器
 *
 */
class HttpServer
{
public:
	static const int MAX_STATIC_PATH = 16;

	static const int ASYNC_RESULT = -1;

	class UploadContext
	{
	public:
	    virtual ~UploadContext() {}
	};

	typedef std::function< int (HttpRequest& request, HttpResult& result) > UploadHandler;

	typedef std::function< int (HttpRequest& request, HttpResult& result)>    Handler;

	typedef Handler	HttpAuth;

	enum WsDataType
	{
		WS_TEXT = 1,
		WS_BINARY = 2,
	};

	typedef std::function< void() >	Task;


public:

	virtual ~HttpServer() {}

	/**
	 * 设置Web根目录, 默认当前目录
	 */
	virtual bool setWebRoot(const char* dirPath) =0;


	virtual bool setUserFile(const char* filePath) =0;

	/**
	 * 设置上传路径
	 * @param dirPath
	 * @return
	 */
	virtual bool setUploadDir(const char* url, const char* dirPath, UploadHandler handler) =0;

	/**
	 * 添加目录
	 * @param url		URL目录
	 * @param dirPath	本地目录
	 * @return true 表示成功
	 */
	virtual bool addDir(const char* url, const char* dirPath, HttpAuth auth = HttpAuth()) =0;

	/**
	 * 添加api路径
	 * @param prefix
	 * @return
	 */
	virtual bool addApi(const char* prefix) = 0;

	/**
	 * 启动
	 * @param ip 本地地址
	 * @param port	本地端口
	 * @param handler	处理器
	 * @return
	 */
	virtual bool start(const char* ip, int port, HttpHandler* defHandler) =0;

	/**
	 * 停止服务
	 */
	virtual void stop() =0;

	/**
	 * 是否启动
	 * @return
	 */
	virtual bool isStarted() =0;

	/**
	 * 异步发送HTTP响应
	 * @param conn
	 * @param result	内容
	 * @return
	 */
	virtual bool sendResponse(HttpConnection* conn, const HttpResult& result) = 0;

	/**
	 * 异步发送内容
	 * @param nc	连接
	 * @param data	数据指针
	 * @param len	数据长度, < 8K
	 * @return
	 */
	virtual bool send(HttpConnection* conn, const void* data, size_t len) =0;

	/**
	 * 启用SSL
	 * @param port      端口
	 * @param caPath    ca证书路径
	 * @param certPath  证书路径
	 * @param keyPath   密钥路径
	 * @return
	 */
	virtual bool enableSsl(int port, const char* caPath, const char* certPath, const char* keyPath) = 0;


	virtual bool getRemoteAddr(HttpConnection* conn, std::string& name) =0;

	/**
	 * 设置上传子目录
	 * @param subUrl	更具体上传URL
	 * @param dirpath   对应文件路径
	 * @return
	 */
	virtual bool setUploadSubDir(const char* subUrl, const char* dirPath) =0;

	/**
	 * 发送给所有 websocket 连接
	 * @param data
	 * @param len
	 */
	virtual void broadcast(WsDataType type, const char* data, size_t len) =0;

	/**
	 * 设置websocket URL 和 鉴权
	 * @param url
	 * @param auth
	 */
	virtual void setWebSocket(const char* url, Handler handler, HttpAuth auth = HttpAuth()) =0;

	/**
	 * 向指定连接发送websocket数据
	 * @param conn
	 * @param type
	 * @param data
	 * @param len
	 * @return
	 */
	virtual bool sendFrame(HttpConnection* conn, WsDataType type, const char* data, size_t len) =0;

	/**
	 * 虚拟文件处理器
	 * @param url	路径
	 * @param handler	处理器
	 */
	virtual void setVirtualFile(const char* url, Handler handler) =0;

	/**
	 * 设置定时任务
	 * @param seconds	间隔, 单位为秒
	 * @param task	任务处理器
	 */
	virtual void setTimerTask(int seconds, Task task) =0;


};



#endif /* HTTPSERVER_H_ */
